package com.cdeledu.唤醒指定线程.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**使用Condition唤醒指定线程
synchronized关键字与wait（）和notify（）/notifyAll（）结合能够实现等待通知模型，但是却面临一个问题，就是，被wait（）唤醒的线程是随机的，而notifyAll（）唤醒的又是所有的，不能唤醒指定的线程。
ReentrantLock借助于Condition就可以实现唤醒指定线程，这样在线程调度上更加灵活。
 * @author DELL
 *
 */
public class MyService {

	private Lock lock = new ReentrantLock();
	private Condition condition  = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	public void await1() {
		try {
			lock.lock();
			System.out.println("执行 await1 方法");
			condition.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
			System.out.println("await1 锁释放了");
		}
	}

	public void await2() {
		try {
			lock.lock();
			System.out.println("执行 await2 方法");
			condition2.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
			System.out.println("await2锁释放了");
		}
	}

	public void signal1() {
		try {
			lock.lock();
			System.out.println("执行signal1方法");
			condition.signal();
			System.out.println("通知了await1 ");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();

		}
	}

	public void signal2() {
		try {
			lock.lock();
			System.out.println("执行signal2方法");
			condition2.signal();
			System.out.println("通知了await2 ");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();

		}
	}

	public static void main(String[] args) {
		MyService service = new MyService();
		ThreadA threadA = new ThreadA(service);
		ThreadAA threadAA = new ThreadAA(service);
		ThreadB threadB = new ThreadB(service);
		ThreadBB threadBB = new ThreadBB(service);

		try {
			threadA.start();
			threadAA.start();
			Thread.sleep(300);
			threadB.start();
			ThreadA.sleep(3000);
			threadBB.start();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

class ThreadA extends Thread{
	private MyService service;
	public ThreadA(MyService service) {
		this.service = service;
	}

	public void run() {
		service.await1();
	}
}

class ThreadAA extends Thread{
	private MyService service;
	public ThreadAA(MyService service) {
		this.service = service;
	}

	public void run() {
		service.await2();
	}
}

class ThreadB extends Thread{
	private MyService service;
	public ThreadB(MyService service) {
		this.service = service;
	}

	public void run() {
		service.signal1();
	}
}

class ThreadBB extends Thread {
	private MyService service;
	public ThreadBB(MyService service) {
		this.service = service;
	}

	public void run() {
		service.signal2();
	}
}
